
// 日志器模块设计
// 抽象日志器基类
// 实现子类同步日志器和异步日志器

#ifndef __LOGGER__
#define __LOGGER__

#include <atomic>
#include <mutex>
#include <stdarg.h>
#include <unordered_map>
#include "util.hpp"
#include "format.hpp"
#include "level.hpp"
#include "message.hpp"
#include "sink.hpp"
#include "looper.hpp"

namespace violet_log
{
    class logger
    {
    public:
        using ptr = std::shared_ptr<logger>;

        logger
        (
            const std::string &logger_name,
            log_level::level level,
            formatter::ptr formatter,
            std::vector<log_sink::ptr> sinks
        ): 
            _logger_name(logger_name),
            _limit_level(level),
            _formatter(formatter),
            _sinks(sinks)
        {}

        // 获取日志器名称
        const string &get_name()
        {
            return _logger_name;
        }

        // 完成构造日志消息对象过程并进行格式化，得到格式化后的日志字符串
        // 之后进行落地输出
        void debug(const std::string &file, size_t line, const std::string &fmt, ...)
        {
            // 通过传入的参数构造日志消息对象，并进行格式化
            // 1.判断当前日志是否达到了输出等级
            if (log_level::level::DEBUG < _limit_level)
            {
                std::cout << "xyz" << std::endl;
                return;
            }
            // 2.对fmt格式化字符串和不定参进行字符串组织，得到日志字符串
            va_list ap;
            va_start(ap, fmt);
            // man vasprintf
            char *res;
            int ret = vasprintf(&res, fmt.c_str(), ap);
            if (ret == -1)
            {
                printf(res);
                std::cout << "对fmt格式化字符串和不定参进行字符串组织失败" << std::endl;
                free(res); // 勿忘
                return;
            }
            va_end(ap);
            serialize(log_level::level::DEBUG, file, line, res);

            free(res); // 勿忘
        }
        void info(const std::string &file, size_t line, const std::string &fmt, ...)
        {
            if (log_level::level::INFO < _limit_level)
                return;
            va_list ap;
            va_start(ap, fmt);
            char *res;
            int ret = vasprintf(&res, fmt.c_str(), ap);
            if (ret == -1)
            {
                printf(res);
                std::cout << "对fmt格式化字符串和不定参进行字符串组织失败" << std::endl;
                free(res); // 勿忘
                return;
            }
            va_end(ap);
            serialize(log_level::level::INFO, file, line, res);
            free(res); // 勿忘
        }
        void warn(const std::string &file, size_t line, const std::string &fmt, ...)
        {
            if (log_level::level::WARN < _limit_level)
                return;
            va_list ap;
            va_start(ap, fmt);
            char *res;
            int ret = vasprintf(&res, fmt.c_str(), ap);
            if (ret == -1)
            {
                printf(res);
                std::cout << "对fmt格式化字符串和不定参进行字符串组织失败" << std::endl;
                free(res); // 勿忘
                return;
            }
            va_end(ap);
            serialize(log_level::level::WARN, file, line, res);
            free(res); // 勿忘
        }
        void error(const std::string &file, size_t line, const std::string &fmt, ...)
        {
            if (log_level::level::ERROR < _limit_level)
                return;
            va_list ap;
            va_start(ap, fmt);
            char *res;
            int ret = vasprintf(&res, fmt.c_str(), ap);
            if (ret == -1)
            {
                printf(res);
                std::cout << "对fmt格式化字符串和不定参进行字符串组织失败" << std::endl;
                free(res); // 勿忘
                return;
            }
            va_end(ap);
            serialize(log_level::level::ERROR, file, line, res);
            free(res); // 勿忘
        }
        void fatal(const std::string &file, size_t line, const std::string &fmt, ...)
        {
            if (log_level::level::FATAL < _limit_level)
                return;
            va_list ap;
            va_start(ap, fmt);
            char *res;
            int ret = vasprintf(&res, fmt.c_str(), ap);
            if (ret == -1)
            {
                printf(res);
                std::cout << "对fmt格式化字符串和不定参进行字符串组织失败" << std::endl;
                free(res); // 勿忘
                return;
            }
            va_end(ap);
            serialize(log_level::level::FATAL, file, line, res);
            free(res); // 勿忘
        }

    protected:
        // 序列化
        void serialize(log_level::level level, const std::string &file, size_t line, const char *res)
        {
            // 3.构造log_message对象
            log_message msg(level, _logger_name, line, file, res);
            // 4.通过格式化工具对log_message进行格式化，得到格式化后的日志字符串
            std::stringstream ss;
            _formatter->format(ss, msg);
            // 5.日志落地
            log(ss.str().c_str(), ss.str().size());
        }

        // 不同的日志器会有不同的落地方式
        virtual void log(const char *data, size_t len) = 0;

    protected:
        std::string _logger_name;                   // 日志器名称
        std::atomic<log_level::level> _limit_level; // 日志器等级限制
        formatter::ptr _formatter;                  // 格式化器
        std::mutex _mutex;                          // 互斥锁
        std::vector<log_sink::ptr> _sinks;          // 落地方式
    };

    // 同步日志器
    // synchronous
    class sync_logger : public logger
    {
    public:
        sync_logger
        (
            const std::string &logger_name,
            log_level::level level,
            formatter::ptr formatter,
            std::vector<log_sink::ptr> sinks
        ):logger(logger_name, level, formatter, sinks) {}

    private:
        void log(const char *data, size_t len)
        {
            std::unique_lock<std::mutex> lock(_mutex); // 勿忘
            if (_sinks.empty())
                return;
            for (auto &x : _sinks)
            {
                x->log(data, len);
            }
        }
    };

    // 异步日志器
    // 继承logger日志器类，对日志操作进行重写
    // 添加的成员：异步工作器
    // 通过异步工作器将日志进行落地
    // 完成后，完善日志器建造者，进行异步日志器安全模式的选择，通过异步日志器的创建
    class async_logger : public logger
    {
    public:
        async_logger
        (
            const std::string &logger_name,
            log_level::level level,
            formatter::ptr formatter,
            std::vector<log_sink::ptr> sinks,
            async_type looper_type
        ):
            logger(logger_name, level, formatter, sinks),
            // 绑定参数，将this指针与real_log绑定，placeholders::_1指定第二个参数使用后续传入的值
            _looper(std::make_shared<async_looper>(std::bind(&async_logger::real_log, this, std::placeholders::_1), looper_type))
        {}

        void log(const char *data, size_t len)
        {
            _looper->push(data, len);
        }

        // 实际落地：将缓冲区中的数据落地
        void real_log(buffer &buf)
        {
            if (_sinks.empty())
                return;
            for (auto &x : _sinks)
            {
                x->log(buf.begin(), buf.readable_size());
            }
        }

    private:
        async_looper::ptr _looper;//异步工作器
    };

    // 设置日志器类型，将不同的日志器类型放到同一个建造者类中建造
    enum class logger_type
    {
        LOGGER_SYNC,
        LOGGER_ASYNC
    };

    // 建造者模式，简化日志器的构建
    // 建造者模式是一种创建型设计模式，使用多个简单的对象一步一步构建成一个复杂的对象
    // 能够将一个复杂的对象的构建与它的表示分离，提供一种创建对象的最佳方式
    // 主要用于解决对象的构建过于复杂的问题
    // 建造者模式主要基于四个核心类实现：抽象产品类、具体产品类、抽象builder类、具体产品的builder类
    // 抽象出建造者基类
    class build_logger
    {
    public:
        build_logger()
            :_logger_type(logger_type::LOGGER_SYNC)
            ,_limit_level(log_level::level::DEBUG)
            ,_async_type(async_type::ASYNC_SAFE)
        {}

        void build_logger_type(logger_type type)
        {
            _logger_type = type;
        }

        void build_logger_name(const std::string &logger_name)
        {
            _logger_name = logger_name;
        }

        void build_logger_limit_level(log_level::level level)
        {
            _limit_level = level;
        }

        void build_formatter(const std::string &pattern)
        {
            _formatter = std::make_shared<formatter>(pattern);
        }

        template <class sink_type, class... Args>
        void build_sink(Args &&...args)
        {
            log_sink::ptr psink = sink_factory::creat<sink_type>(std::forward<Args>(args)...);
            _sinks.push_back(psink);
        }

        // 使用异步日志器的不安全模式
        void build_enable_async_unsafe()
        {
            _async_type = async_type::ASYNC_UNSAFE;
        }

        virtual logger::ptr build() = 0;

    protected:
        logger_type _logger_type;          // 日志器类型
        std::string _logger_name;          // 日志器名称
        log_level::level _limit_level;     // 日志器等级限制
        formatter::ptr _formatter;         // 格式化器
        std::vector<log_sink::ptr> _sinks; // 落地方式
        async_type _async_type;            // 异步日志器的模式
    };

    // 子类：局部建造者
    class local_build_logger : public build_logger
    {
    public:
        logger::ptr build()
        {
            assert(_logger_name.empty() == false);
            if (_formatter.get() == nullptr)
            {
                _formatter = std::make_shared<formatter>();
            }
            if (_sinks.empty())
            {
                build_sink<stdout_sink>();
            }
            if (_logger_type == logger_type::LOGGER_ASYNC)
            {
                return std::make_shared<async_logger>(_logger_name, _limit_level, _formatter, _sinks, _async_type);
            }
            return std::make_shared<sync_logger>(_logger_name, _limit_level, _formatter, _sinks);
        }
    };

    // 日志器管理器：对所有日志器进行管理，并有一个默认日志器
    // 设计为单例模式，可在程序的任意位置获取到单例对象，获取其中的日志器进行输出
    // 成员：
    // 1.默认日志器
    // 2.日志器哈希表
    // 3.互斥锁：保证日志器哈希表的线程安全
    // 须实现的接口：
    // 1.获取默认日志器
    // 2.获取指定名称日志器
    // 3.判断日志器是否在哈希表中
    // 4.添加日志器

    class logger_manage
    {
    public:
        // 获取单例对象，懒汉模式
        static logger_manage &get_instance()
        {
            // C++11保证静态局部变量的初始化是线程安全的
            static logger_manage lm;
            return lm;
        }

        // 获取logger，传入logger名称
        logger::ptr get_logger(const string &logger_name)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            // unordered_map<string, logger::ptr>::iterator it = _logger_map.find(logger_name);
            auto it = _logger_map.find(logger_name);
            if (it == _logger_map.end())
                return logger::ptr();
            return it->second;
        }

        // 获取默认日志器
        logger::ptr default_logger()
        {
            return _default_logger;
        }

        // logger是否存在，传入logger名称
        bool exist(const string &logger_name)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto it = _logger_map.find(logger_name);
            if (it == _logger_map.end())
            {
                std::cout << "名为" << logger_name << "的日志器不存在" << std::endl;
                return false;
            }
            return true;
        }

        // 添加logger，传入logger的智能指针
        void add_logger(const logger::ptr &plogger)
        {
            if (exist(plogger->get_name()))
                return;
            std::unique_lock<std::mutex> lock(_mutex);
            _logger_map[plogger->get_name()] = plogger;
        }

    private:
        logger_manage()
        {
            std::unique_ptr<build_logger> b(new local_build_logger());
            b->build_logger_name("default");
            _default_logger = b->build();
            _logger_map["default"] = _default_logger;
        }
        logger_manage(const logger_manage& s) = delete;
        logger_manage& operator=(const logger_manage& s) = delete;
        ~logger_manage() {}

    private:
        logger::ptr _default_logger;                              // 默认日志器
        std::unordered_map<std::string, logger::ptr> _logger_map; // 日志器哈希表
        std::mutex _mutex;                                        // 互斥锁
    };

    // 子类：全局建造者
    class global_build_logger : public build_logger
    {
    public:
        logger::ptr build()
        {
            if(_logger_name.empty())
            {
                _logger_name = "default";
            }
            if (_formatter.get() == nullptr)
            {
                _formatter = std::make_shared<formatter>();
            }
            if (_sinks.empty())
            {
                build_sink<stdout_sink>();
            }
            logger::ptr logger_ret;
            if (_logger_type == logger_type::LOGGER_ASYNC)
                logger_ret = std::make_shared<async_logger>(_logger_name, _limit_level, _formatter, _sinks, _async_type);
            else
                logger_ret = std::make_shared<sync_logger>(_logger_name, _limit_level, _formatter, _sinks);
            logger_manage::get_instance().add_logger(logger_ret);
            return logger_ret;
        }
    };
}

#endif